﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace ICodeShare.UI.Interactivity
{
    /// <summary>
    /// 文本验证行为
    /// </summary>
    /// <example>
    /// 1.在Xaml中使用：
    ///   1)在xaml中添加引用  
    ///       xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    ///       xmlns:behaviors="http://schemas.extended.wpf.com/interactivity"
    ///   2)在TextBox元素上设置行为
    ///             <TextBox Width="240" Height="50">
    ///                 <i:Interaction.Behaviors>
    ///                     <behaviors:TextValidateBehavior InvalidPattern="[^a-z0-9A-Z_]" UpdateBindingWhenTextChanged="True"></behaviors:TextValidateBehavior>
    ///                 </i:Interaction.Behaviors>
    ///             </TextBox>
    ///   3)正则表达式设置，设置InvalidPattern="[^a-z0-9A-Z_]"          
    ///   4)如果需要在Text属性改变时立即更新绑定，设置UpdateBindingWhenTextChanged="True" 
    /// 2.常用正则表达式：
    ///   1) [^\d\.]        ——只能输入数字和小数点
    ///   2) [^\d]          ——只能输入数字
    ///   3) [^a-z0-9A-Z_]  ——只能输入数字、字母和下划线
    /// </example>
    public class TextValidateBehavior : Behavior<TextBox>
    {
        #region 依赖属性

        #region InvalidPattern

        /// <summary>
        /// 正则表达式
        /// </summary>
        public string InvalidPattern
        {
            get
            {
                return (string)this.GetValue(InvalidPatternProperty);
            }
            set
            {
                this.SetValue(InvalidPatternProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for InvalidPattern.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvalidPatternProperty =
            DependencyProperty.RegisterAttached("InvalidPattern", typeof(string), typeof(TextValidateBehavior), new PropertyMetadata(string.Empty, OnInvalidPatternPropertyChanged));

        private static void OnInvalidPatternPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = d as TextBox;
            string pattern = e.NewValue as string;
        }
        #endregion

        #region UpdateBindingWhenTextChanged

        /// <summary>
        /// 输入内容改变时更新绑定
        /// </summary>
        public bool UpdateBindingWhenTextChanged
        {
            get
            {
                return (bool)this.GetValue(UpdateBindingWhenTextChangedProperty);
            }
            set
            {
                this.SetValue(UpdateBindingWhenTextChangedProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for UpdateBindingWhenTextChanged.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UpdateBindingWhenTextChangedProperty =
            DependencyProperty.RegisterAttached("UpdateBindingWhenTextChanged", typeof(bool), typeof(TextValidateBehavior), new PropertyMetadata(false, OnUpdateBindingWhenTextChangedPropertyChanged));

        private static void OnUpdateBindingWhenTextChangedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = d as TextBox;
            bool value = (bool)e.NewValue;
        }
        #endregion

        #region OriCursorPosition
        /// <summary>
        /// 光标起始位置
        /// </summary>
        private int OriCursorPosition
        {
            get
            {
                return (int)this.GetValue(OriCursorPositionProperty);
            }
            set
            {
                this.SetValue(OriCursorPositionProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for FilterParameters.  This enables animation, styling, binding, etc...
        private static readonly DependencyProperty OriCursorPositionProperty =
            DependencyProperty.RegisterAttached("OriCursorPosition", typeof(int), typeof(TextValidateBehavior), new PropertyMetadata(0, OnOriCursorPositionPropertyChanged));



        private static void OnOriCursorPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        #endregion

        #endregion

        #region 重写方法

        #region 注册事件
        /// <summary>
        /// 注册事件
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.KeyUp += AssociatedObject_KeyUp;
            this.AssociatedObject.KeyDown += AssociatedObject_KeyDown;
        }

        #endregion

        #region 注销事件
        /// <summary>
        /// 注销事件
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
            this.AssociatedObject.KeyDown -= AssociatedObject_KeyDown;
        }
        #endregion

        #endregion

        #region 事件
        /// <summary>
        /// KeyUp时，将非法字符删掉，并将TextBox的SelectionStart值还原为KeyDown时的值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
        {
            TextBox textBox = sender as TextBox;

            Debug.Assert(textBox != null, "sender should be a non-null TextBox!");
            Debug.Assert(e != null, "e should not be null!");


            int position = this.OriCursorPosition;
            string pattern = this.InvalidPattern;
            if (!string.IsNullOrEmpty(pattern))
            {
                if (Regex.IsMatch(textBox.Text, pattern))
                {
                    textBox.Text = Regex.Replace(textBox.Text, pattern, "");
                    if (position > textBox.Text.Length || e.Key == Key.Space)
                        textBox.SelectionStart = textBox.Text.Length;
                    else
                        textBox.SelectionStart = position;
                }
                else
                {
                    if (this.UpdateBindingWhenTextChanged)
                    {
                        BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
                        if (be != null)
                            be.UpdateSource();
                    }
                }
            }
            else
            {
                if (this.UpdateBindingWhenTextChanged)
                {
                    BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
                    if (be != null)
                        be.UpdateSource();
                }
            }
        }

        /// <summary>
        /// KeyDown时，记录TextBox的SelectionStart
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
        {
            TextBox textBox = sender as TextBox;

            Debug.Assert(textBox != null, "sender should be a non-null TextBox!");
            Debug.Assert(e != null, "e should not be null!");

            this.OriCursorPosition = textBox.SelectionStart;
        }

        #endregion
    }
}
